package com.entity;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.csource.common.MyException;
import org.csource.fastdfs.FileInfo;

import com.alibaba.fastjson.JSON;
import com.servlet.My;

import hyl.core.MyFun;
import hyl.core.conf.MyConst;
import hyl.core.io.MyFile;
import hyl.core.safe.MyHash;


/**
 * 文件
 * 
 * @author 37798955@qq.com
 *
 */
public class FileComp {
	public static String UPLOADCHECKCODE = MyConst.getInstance().get("UPLOAD_PASS").trim();
	private static String FileDir = "/uploaddir";
	// 指定存储目录
	private static String FILESAVEPATH = null;
	// web 工程目录
	private static String WEBSAVEPATH = null;
	// web工程 下存储上传文件的目录
	// 存储位置字典
	public static final int I位置_项目中 = 0;
	public static final int I位置_项目外 = 1;
	public static final int I位置_分布式 = 2;
	public static Long MAXFileSIZE_KB = 2097152L;// 2048L*1024;
	private static FastDfsApi fastdfsApi = null;
	static {
		Long l = MyFun.str2long(MyConst.getInstance().get("MAXFILESIZE_KB"));
		int i = MyFun.str2int(MyConst.getInstance().get("IS_FDFS"));
		// System.out.println(i);
		if (i == 1) {
			fastdfsApi = FastDfsApi.getInstance();
		}

		if (l != null)
			MAXFileSIZE_KB = l * 1024;
	}

	public static void exit() {
		if (fastdfsApi == null)
			return;
		fastdfsApi.close();
	}

	/**
	 *
	 * 如果在system.ini 设置了 SRV_UPLOAD_PATH 值 就使用该值 否则使用 web工作目录下的 /upload0/ 目录作为固定存储
	 * 
	 * @return
	 */
	public static String getPath() {
		if (FILESAVEPATH == null) {
			// 获取服务器 端文件的固定存储路径
			FILESAVEPATH = MyConst.getInstance().get("UPLOAD_SAVE_PATH").trim();
		}
		return FILESAVEPATH;
	}

	public static String getPathWeb(HttpServletRequest req) {
		if (WEBSAVEPATH == null) {
			WEBSAVEPATH = req.getServletContext().getRealPath(FileDir);
		}
		return WEBSAVEPATH;
	}

	/** 解析part中的文件名 */
	public static String extractFilename(Part part) {
		String header = part.getHeader("content-disposition");
		// System.out.println(header);
		String[] elements = header.split(";");
		for (String element : elements) {
			if (element.trim().startsWith("filename")) {
				String el = MyFun.str2filename(element.substring(element.indexOf('=') + 1));

				// System.out.println(el);
				try {
					return new String(el.getBytes("utf-8"));
					// return URLEncoder.encode(el, "UTF-8");
				} catch (Exception e) {
				}
			}
		}
		return null;
	}

	/** 解析part中的文件名 */
	public static String getFileName(Part part) {
		String header = part.getHeader("Content-Disposition");
		int i=header.indexOf("filename=\"");
		if (i<0) return null;
		String fileName = header.substring(i + 10, header.lastIndexOf("\""));
		String el = MyFun.str2filename(fileName);
		return el;
	}

	/**
	 * 接收用户文件,返回上传文件的属性集合
	 *
	 * @param req  请求路径
	 * @param dir  文件子目录 <br>
	 * @param type 文件类型 <br>
	 * @param 安全   是否需要安全存放 如果安全=1 那么表示需要另存,需要通过servlet 方式访问<br>
	 * @return 上传文件的属性集合
	 * @throws IOException
	 * @throws ServletException
	 * @throws MyException
	 */
	public static String upload(HttpServletRequest req, String 系统, String 前缀, String 后缀, int type,
			int 安全) throws IOException, ServletException {
		String dirpath = MyFile.getSavePath(系统, 前缀, 后缀);
		// System.out.println("dirpath="+dirpath);
		String 存储目录, 下载目录;
		
		if (安全 == 0) {
			// 默认 存储在web 工程目录的 /upload下面
			存储目录 = getPathWeb(req) + dirpath;
			下载目录 = My.getBasePath(req) + FileDir + dirpath;
			 return upload0(req, 存储目录, 下载目录, type);
		} else if (安全 == 2 && (fastdfsApi != null)) {
			// 所以没有存储目录
			下载目录 = My.getBasePath(req) + "/down/df";
			return upload1(req, 下载目录);
		}

		// 如果需要安全存储 ,那么另存到指定目录
		存储目录 = getPath() + dirpath;
		下载目录 = My.getBasePath(req) + "/down/f" + dirpath;

		return upload0(req, 存储目录, 下载目录, type);
	}
	
	/**
	 * 上传到本地
	 * 
	 * @param req
	 * @param dirpath
	 * @param 存储目录    末尾不带 /
	 * @param 下载目录    末尾不带 /
	 * @param type
	 * @return
	 * @throws IOException
	 * @throws ServletException
	 */
	public static String upload0(HttpServletRequest req, //
			String 存储目录, String 下载目录, int type) throws IOException, ServletException {

		List<Map<String, Object>> filespath = new ArrayList<>();
		File newfile = null;
		MyFile.openDir(存储目录);
		Iterator<Part> parts = req.getParts().iterator();
		while (parts.hasNext()) {// 遍历写文件

			Map<String, Object> fileinfo = new HashMap<>();
			Part part = parts.next();
			Long srcsize = part.getSize();			
			
			String oldfilename = getFileName(part);
			if (MyFun.isEmpty(oldfilename))
				continue;
			if (srcsize>MAXFileSIZE_KB) 			
				return oldfilename+"文件太大了,请先压缩处理";
			System.out.println("oldfilename:"+oldfilename);
			String fname = MyFile.getNewName(oldfilename, type);

			//System.out.println("存储目录:"+存储目录);
			// System.out.println("newfilename:"+fname);
			// 保存新文件
			try {
				newfile = MyFile.saveFile(part.getInputStream(), 存储目录, fname);
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			}
		
			fileinfo.put("path", 下载目录 + '/' + newfile.getName());
			fileinfo.put("realpath", 存储目录 + '/' + fname);
			fileinfo.put("oldsize", srcsize);
			fileinfo.put("newsize", newfile.length());
			fileinfo.put("oldname", oldfilename);
			fileinfo.put("md5",  MyHash.getInsMD5().parse16(newfile));
			// fileinfo.put("md5", "22");
			// System.out.println(JSON.toJSONString(fileinfo));

			filespath.add(fileinfo);
		}

		
		return JSON.toJSONString(filespath);

	}

	/**
	 * 分布式上传
	 * 
	 * @param req
	 * @param 下载目录
	 * @return
	 */
	public static String upload1(HttpServletRequest req, String 下载目录) {
		try {

			// req.getServletContext().setSessionTimeout(30000);
			// requestFactory.setConnectTimeout(30000);// 设置超时
			// requestFactory.setReadTimeout(30000);
			Iterator<Part> parts = req.getParts().iterator();

			List<Map<String, Object>> filespath = new ArrayList<>();

			while (parts.hasNext()) {// 遍历写文件
				Map<String, Object> fileinfo = new HashMap<>();
				Part part = parts.next();
				long srcsize = part.getSize();				
				String oldfilename = getFileName(part);
				if (srcsize>MAXFileSIZE_KB) 			
					return oldfilename+"文件太大了,请先压缩处理";
				
				if (MyFun.isEmpty(oldfilename))
					continue;
				InputStream is = part.getInputStream();
				String[] dirs = fastdfsApi.upload(is, oldfilename, srcsize);

				String dfspath = "/" + MyFun.join(dirs, "/");

				// System.out.println(dfspath);

				FileInfo finfo = fastdfsApi.getFileInfo(dfspath);
				fileinfo.put("path", 下载目录 + dfspath); //
				fileinfo.put("realpath", dfspath);// fdfs 路径
				fileinfo.put("oldsize", srcsize);
				fileinfo.put("newsize", finfo.getFileSize());
				fileinfo.put("oldname", oldfilename);
				fileinfo.put("md5", finfo.getCrc32());

				filespath.add(fileinfo);
			}
			return JSON.toJSONString(filespath);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "文件上传异常";
	}

	/**
	 * 下载文件
	 * 
	 * @param 下载路径
	 * @param 分布式
	 * @param req
	 * @param res
	 * @return
	 */
	public static boolean download(String 下载路径, int 分布式, HttpServletRequest req, HttpServletResponse res) {
		String filename = 下载路径.substring(下载路径.lastIndexOf('/') + 1);
		// System.out.println(下载路径);
		// System.out.println(filename);
		// 清空response
		res.reset();
		String extname = MyFile.getFileExt(filename).toLowerCase();

		// 设置response的Header
		// res.addHeader("Content-Disposition", "attachment;filename=" + filename);
		// 如果是图片或者多媒体需要设置
		if (extname.equals("jpg") || extname.equals("jpeg"))
			res.setHeader("content-type", "image/jpeg");
		else if (extname.equals("gif"))
			res.setContentType("image/gif");
		else if (extname.equals("png"))
			res.setContentType("image/png");
		else if (extname.equals("txt"))
			res.setContentType("text/plain");
		else if (extname.equals("xml"))
			res.setContentType("text/xml");
		else if (extname.equals("json"))
			res.setContentType("application/json");
		else if (extname.equals("pdf"))
			res.setContentType("application/pdf");
		else
			res.setContentType("application/octet-stream");

		// response.setContentType("multipart/form-data");是上传文件之时使用的：
		if (fastdfsApi == null) {
			// 如果没有分布式服务器 只能使用本地下载
			// System.out.println("本地文件下载..");
			return download0(下载路径, req, res);
		} else {
			if (分布式 == 0)
				return download0(下载路径, req, res);
			else {
				// System.out.println("分布式文件下载..");
				return download1(下载路径, req, res);
			}
		}

	}

	/**
	 * 从本地文件库下载
	 * 
	 * @param downLoadPath
	 * @param req
	 * @param res
	 * @return
	 */
	public static boolean download0(String downLoadPath, HttpServletRequest req, HttpServletResponse res) {

		String filepath = getPath() + downLoadPath;

		File file = new File(filepath);
		if (!file.exists()) {
			return false;
		} else {
			// 获取文件的长度
			Long fileLength = file.length(); // 设置输出长度
			res.addHeader("Content-Length", fileLength.toString());
			try {
				MyFile.copyFile(new FileInputStream(file), res.getOutputStream());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return true;
		}
	}

	/**
	 * 从分布式文件服务器下载
	 * 
	 * @return
	 */
	public static boolean download1(String downLoadPath, HttpServletRequest req, HttpServletResponse res) {

		FileInfo fi = null;
		try {
			fi = fastdfsApi.getFileInfo(downLoadPath);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (MyException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		if (fi == null)
			return false;
		else {
			long 开始位置 = MyFun.str2long(req.getParameter("offset"));
			long 结束位置 = MyFun.str2long(req.getParameter("end"));

			if (结束位置 > 0 && 结束位置 < 开始位置)
				return false;

			// 获取文件的长度
			Long fileLength = fi.getFileSize();
			if (结束位置 == 0)
				结束位置 = fileLength;

			// 设置输出长度
			res.addHeader("Content-Length", fileLength.toString());
			DownCallback dcb = new DownCallback(res);
			fastdfsApi.download(downLoadPath, 开始位置, 结束位置, dcb);

			return true;
		}

	}

}
